#ifndef UTILS_H_
#define UTILS_H_

using namespace std;

/* C++ Libs */
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <vector>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdexcept>
#include <cmath>


/* Mis librerias */
#include "ListaEnlazada.cpp"


/* Funciones utilitarias */

void var_dump_string(const char* text , uInt maxSize){
	char* actual = (char*)text;
	uInt cont = 0;
	while(true){
		printf("[%d] (%d) => '%c' : '%02X'\n",cont,(uInt)actual,*actual,*actual);
		if( *actual == 0 ) break;
		
		cont++;
		if(cont == maxSize) break;
		actual++;
	}
}

bool last_char_is_null(const char* text , uInt textLength){
	char* last = (char*)text + textLength - 1;
	return (char)0xa == *last;
}


string string_to_hex(const string& input){
    static const char* const lut = "0123456789ABCDEF";
    size_t len = input.length();

    string output;
    output.reserve(2 * len);
    for (size_t i = 0; i < len; ++i)
    {
        const char c = input[i];
        output.push_back(lut[c >> 4]);
        output.push_back(lut[c & 15]);
    }
    return output;
}

string hex_to_string(const string& input){
    static const char* const lut = "0123456789ABCDEF";
    size_t len = input.length();
    if (len & 1) throw invalid_argument("odd length");

    string output;
    output.reserve(len / 2);
    for (size_t i = 0; i < len; i += 2)
    {
        char a = input[i];
        const char* p = lower_bound(lut, lut + 16, a);
        if (*p != a) throw invalid_argument("not a hex digit");

        char b = input[i + 1];
        const char* q = lower_bound(lut, lut + 16, b);
        if (*q != b) throw invalid_argument("not a hex digit");

        output.push_back(((p - lut) << 4) | (q - lut));
    }
    return output;
}

// Convierte int a string
string intToString(int i)
{
	stringstream s;
	s<<i;
	return s.str();
}

// Convierte un entero a su representacion binaria en formato string.
string binary(int K){
	string fBin = "", addZero = "";
	int a,b = K, binSize = 0;
	string intToString(int);

	while(b > 0){
		a = b % 2;
		b = b / 2;

		fBin += intToString(a);
	}

	binSize = 8 - fBin.length();

	//add trailing zeros
	for(int i=0;i<binSize;i++){
		addZero += "0"; 
	}

	if(fBin.length()<8){
		fBin+=addZero; 
	}

	//reverse the string of binary
	int x = fBin.length(); //takes length of string
	for(int y = x; y >= (x/2)+1; y--){ //for loop arranging the string
		swap(fBin[x-y],fBin[y-1]); // swaps letters
	}

	return fBin;
}


// Convierte a codigo gamma un string que representa un binario
// ejemplo "101" lo codifica en "00101"
string binStringToGamma( const char* bin ){
	char* actual = (char*)bin;
	// Quito los 0 que pueda llegar a tener al comienzo
	while( (*actual == '0') and (*actual != '\0') ) actual++;
	
	uInt length = strlen(actual);
	
	string gamma;
	
	while( length > 1 ){
		gamma.append("0");
		length--;
	}
	
	return gamma.append(actual);
}

string intToGamma( uInt decimalNumber ){
	string binaryNumber = binary(decimalNumber);
	return binStringToGamma( binaryNumber.c_str() );
}

// String es un texto binario ej: "10011001"
int stringBinToInt( char* string ){
	uInt length = strlen(string);
	char* iterador = string + length - 1;
	
	short cont = 0;
	int result = 0;
	
	while( iterador >= string ){
		
		if( *iterador == '1' ){
			result += pow(2, cont);
		}
		
		cont++;
		iterador--;
	}
	return result;
}

#endif /* UTILS_H_ */
